package br.ufrn.opencopi.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 * Armazena apenas o nome do serviço, sua uri, se eh context service e a
 * location (em caso de ser context service).
 * 
 * @author fred
 * 
 */
public class ServiceDependenciesDB {
	private static Connection connection = null;
	private static final Logger log = Logger
			.getLogger(ServiceDependenciesDB.class);
	private static Map<String, List<String>> dependenciesLocator = new HashMap<String, List<String>>();

	private static Connection getConnection() {
		try {
			if (connection != null && !connection.isClosed())
				return connection;
			else
				Class.forName("org.h2.Driver");
			connection = DriverManager
					.getConnection("jdbc:h2:~/test", "sa", "");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return connection;
	}

	/**
	 * Inserts the dependencies of a service
	 * 
	 * @param uriDependentService
	 * @param services
	 * @throws SQLException
	 */
	public static void insertDependenciesByService(String uriDependentService,
			List<String> services) throws SQLException {
		Connection connection = null;
		PreparedStatement pstm = null;
		String uriMainService = null;
		dependenciesLocator.put(uriDependentService, services);
		for (int i = 0; i < services.size(); i++) {
			try {
				uriMainService = services.get(i);
				connection = getConnection();
				String sql = "insert into servicedependencies (dependentserviceuri, serviceuri) "
						+ "values (?, ?)";
				pstm = connection.prepareStatement(sql);

				pstm.setString(1, uriDependentService);
				pstm.setString(2, uriMainService);

				pstm.execute();
				pstm.close();
			} catch (Exception e) {
				System.err
						.println("Erro: ServiceDependenciesDB/insertServiceDependencies()");
				e.printStackTrace();
			} finally {
				pstm.close();
				connection.close();
			}
		}
	}

	/**
	 * Lists the dependencies of a service
	 * 
	 * @param dependentServiceUri
	 * @return
	 * @throws SQLException
	 */

	public static List<String> listServiceDependencies(
			String dependentServiceUri) throws SQLException {
		List<String> dependencies = dependenciesLocator
				.get(dependentServiceUri);
		if (dependencies != null) {
			log.debug("Return dependencies from Locator");
			return dependencies;
		}
		Connection connection = null;
		PreparedStatement pstm = null;
		ResultSet result = null;
		List<String> mainServicesURI = new ArrayList<String>();

		try {
			connection = getConnection();
			String sql = "select * from servicedependencies where dependentserviceuri = '"
					+ dependentServiceUri + "' order by dependentserviceuri";

			pstm = connection.prepareStatement(sql);
			result = pstm.executeQuery();

			while (result.next())
				mainServicesURI.add(result.getString("serviceuri"));

		} catch (Exception e) {
			System.err
					.println("Erro: ServiceDependenciesDB/listServiceDependencies()");
			e.printStackTrace();
		} finally {
			result.close();
			pstm.close();
			connection.close();
		}
		dependenciesLocator.put(dependentServiceUri, mainServicesURI);
		return mainServicesURI;
	}

	/**
	 * Removes all dependencies of a service
	 * 
	 * @param depServUri
	 * @throws SQLException
	 */
	public static void removeServiceDependenciesByDependentService(
			String depServUri) throws SQLException {
		Connection connection = null;
		PreparedStatement pstm = null;
		dependenciesLocator.remove(depServUri);
		try {
			// removendo o serviço em si
			connection = getConnection();
			String sql = "delete from servicedependencies where dependentserviceuri = ?";
			pstm = connection.prepareStatement(sql);

			pstm.setString(1, depServUri);

			pstm.execute();

		} catch (Exception e) {
			System.err
					.println("Erro: ServiceDependenciesDB/removeServiceDependenciesByDependentService()");
			e.printStackTrace();
		} finally {
			pstm.close();
			connection.close();
		}
	}

	/**
	 * Removes a exact service dependence
	 * 
	 * @param depServUri
	 * @param serviceUri
	 * @throws SQLException
	 */
	public static void removeServiceDependency(String depServUri,
			String serviceUri) throws SQLException {
		Connection connection = null;
		PreparedStatement pstm = null;
		// TODO: Verificar esta construção
		dependenciesLocator.remove(serviceUri);
		try {
			// removendo o serviço em si
			connection = getConnection();
			String sql = "delete from servicedependencies where dependentserviceuri = ? & serviceuri = ?";
			pstm = connection.prepareStatement(sql);

			pstm.setString(1, depServUri);
			pstm.setString(2, serviceUri);

			pstm.execute();

		} catch (Exception e) {
			System.err
					.println("Erro: ServiceDependenciesDB/removeServiceDependency()");
			e.printStackTrace();
		} finally {
			pstm.close();
			connection.close();
		}
	}

}
